package com.jiebao.scan;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

import android_serialport_api.SerialPort;


public class BarcodeManager {

	public final static String TAG = "BarcodeManager";

	private static BarcodeManager instance;
	private static Object lock = new Object();
	protected SerialPort mSerialPort;
	private boolean begin;
	private long scan_time_limit = 200; // 扫描间隔控制
	private long scan_time = 6000;// 扫描间隔时间
	private long scan_preTime;
	private long scan_curTime;

	// 控制
	protected OutputStream mOutputStream;
	private InputStream mInputStream;
	private ReadThread mReadThread;
	private Callback onDataListener;

	private ScanThread scanThread;
	public static boolean isContinues = false;
	private boolean isScan = false; // 扫描头状态 ture:出光 false:收光
	private static boolean isReceive = false; // 控制扫描串口读取线程状态 ture:接受数据
												// false:停止接受数据
	private boolean is_SerialPortOpen = false; // 是否打开串口
	private volatile static boolean isCutData = false; // 是否为系统分割数据
	private long lastTime = 0;

	private File trigFile = new File("/proc/jbcommon/gpio_control/scan_switch");// 写"0"出光，写“1”关闭
	private File power = new File("/proc/jbcommon/gpio_control/ir_en");
	private File openCom = new File("/proc/jbcommon/gpio_control/scan_reset");
	private static String serialPort_Path = "/dev/ttyMT1"; // 串口地址

	private static byte[] cutData_buffer = null;
	private static int cutData_buffer_size;

	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			default:
				break;
			}
		};
	};

	private BarcodeManager() {
	}

	public static BarcodeManager getInstance() {
		if (null == instance) {
			synchronized (lock) {
				if (null == instance) {
					instance = new BarcodeManager();
				}
			}
		}
		return instance;
	}

	private void openserialPort(String port, int baudrate, int bits,
			char event, int stop) {
		try {
			mSerialPort = this.getSerialPort(port, baudrate, bits, event, stop);
			mOutputStream = mSerialPort.getOutputStream();
			mInputStream = mSerialPort.getInputStream();

			begin = true;
			mReadThread = new ReadThread();
			mReadThread.start();

		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IOException e) {

			e.printStackTrace();
		} catch (InvalidParameterException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 打开条码设备，调用此方法将初始化扫描设备
	 */
	public void Barcode_Open(Context context, Callback dataReceive) {
		this.onDataListener = dataReceive;
		if (!is_SerialPortOpen) {
			openserialPort(serialPort_Path, 115200, 8, 'N', 1);  // Scanner 3680
			//openserialPort(serialPort_Path, 9600, 8, 'N', 1); //Scanner 4313
			is_SerialPortOpen = true;
		}

		mHandler.post(initRunnable);
	}


	/**
	 * 关闭条码设备
	 */
	public void Barcode_Close() {
		Barcode_Continue_Stop();
		begin = false;
		Barcode_Stop();// 保证HONEYWELL的头上电时不出光
		power("0");
		this.close();
		if (null != mReadThread) {
			notifyReader();
			mReadThread = null;
		}
		is_SerialPortOpen = false;
	}

	/**
	 * 闭光停止扫描
	 */
	public synchronized void Barcode_Continue_Stop() {
		if (scanThread != null) {
			scanThread.interrupt();
			scanThread.run = false;
		}
		isContinues = false;
		scanThread = null;
	}

	private class ScanThread extends Thread {
		public boolean run;
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while (run) {
				try {
					if (is_SerialPortOpen) {
						Barcode_Start();
						sleep(3000);
						if (is_SerialPortOpen) {
							Barcode_Stop();
						}
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block\
					try {
						sleep(scan_time_limit);
					} catch (InterruptedException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					e.printStackTrace();
				}
			}
			if (is_SerialPortOpen) {
				Barcode_Stop();
				isContinues = false;
			}
		}
	}

	private void notifyScanReader() {
		if (scanThread != null && scanThread.isAlive()) {
			scanThread.interrupt();
		}
	}

	/**
	 * 出光开始扫描
	 */
	public synchronized void Barcode_Start() {
		scan("1");
		setIsScan(true);
	}

	/**
	 * 闭光停止扫描
	 */
	public synchronized void Barcode_Stop() {
		com("0");
		if (isScan()) {
			scan("0");
			setIsScan(false);
		}
	}

	/**
	 * 设置出光收光状态
	 *
	 * @param isScan
	 *            ture:出光 <code>false</code>:收光
	 */
	private void setIsScan(boolean isScan) {
		this.isScan = isScan;
	}

	/**
	 * 获取出光收光状态
	 *
	 *            ture:出光 <code>false</code>:收光
	 */
	private boolean isScan() {
		return isScan;
	}

	/**
	 * 出光、收光
	 *
	 * @param trig
	 *            1拉高，关闭；0拉低，打开
	 */
	private synchronized void scan(String trig) {
		// 两次触发信号的间隔时间不低于70ms
		scan_curTime = System.currentTimeMillis();
		if (scan_curTime - scan_preTime < 120) {
			doScan(trig);
		} else {
			doScan(trig);
		}
	}

	private void doScan(String trig) {
		if (trig.equals("1")) {
			setIsReceive(true);
			mHandler.removeCallbacks(stopReceice);
			mHandler.postDelayed(countdown, scan_time);
		} else {
			// isReceive = false;
			mHandler.postDelayed(stopReceice, 1000);
			mHandler.removeCallbacks(countdown);
		}

		notifyReader();
		writeFile(trigFile, trig);
		scan_preTime = scan_curTime;
	}

	private void notifyReader() {
		if (mReadThread != null && mReadThread.isAlive()) {
			mReadThread.interrupt();
		}
	}

	private SerialPort getSerialPort(String port, int baudrate, int bits,
			char event, int stop) throws SecurityException, IOException,
			InvalidParameterException {
		if (mSerialPort == null) {
			if ((port.length() == 0) || (baudrate == -1)) {
				throw new InvalidParameterException();
			}

			mSerialPort = new SerialPort(new File(serialPort_Path), baudrate, bits, event, stop, 0);
		}
		return mSerialPort;
	}

	/**
	 * 扫描数据回调接口 buffer：扫描数据byte数组 ， codeId : 条码类型
	 */
	public interface Callback {
		/**
		 * 扫描数据返回
		 *
		 * @param buffer
		 *            条码数据
		 * @param codeId
		 *            条码类型
		 * @param errorCode
		 *            错误码
		 */
		public void Barcode_Read(byte[] buffer, String codeId, int errorCode);
		public void Barcode_timeout(long timeout);
	}

	private class ReadThread extends Thread {
		@Override
		public void run() {
			super.run();
			while (begin) {
				if (isReceive) {
					int size;
					try {
						if (mInputStream == null)
							return;
						int cout = mInputStream.available();
						if (cout > 0) {
							long nowTime = System.currentTimeMillis();
							if (nowTime - lastTime <= 20) {
								isCutData = true;
								mHandler.removeCallbacks(sendBuffer);
							} else {
								isCutData = false;
							}
						} else {
							continue;
						}
						int temp = 0;
						while (begin) {
							if (mInputStream == null)
								return;
							try {
							} catch (Exception e) {
								e.printStackTrace();
								break;
							}
							cout = mInputStream.available();
							if (temp == cout) {
								break;
							}
							temp = cout;
						}

						if (mInputStream == null)
							return;
						cout = mInputStream.available();
						byte[] buffer = new byte[cout];
						size = mInputStream.read(buffer);

						if (size > 0) {
							if (onDataListener != null) {
								if (!isCutData) {
									cutData_buffer = buffer;
									cutData_buffer_size = size;
								} else {
									if (null != cutData_buffer) {
										byte[] data3 = new byte[cutData_buffer.length + buffer.length];
										System.arraycopy(cutData_buffer, 0, data3, 0, cutData_buffer.length);
										System.arraycopy(buffer, 0, data3, cutData_buffer.length, buffer.length);
										cutData_buffer = new byte[data3.length];
										cutData_buffer = data3;
										cutData_buffer_size += size;
									}
								}
								isCutData = false;
								mHandler.postAtTime(sendBuffer, SystemClock.uptimeMillis() + 19);//59
							}
							lastTime = System.currentTimeMillis();
						}
					} catch (IOException e) {
						e.printStackTrace();
						return;
					} catch (Exception e) {
						// TODO: handle exception
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * 定时检查缓存区数据，处理缓存区数据
	 */
	private Runnable sendBuffer = new Runnable() {
		@Override
		public void run() {
			// TODO Auto-generated method stub
			if (!isCutData) {
				dealData(cutData_buffer, cutData_buffer_size);
			}
		}
	};

	/**
	 * 关闭串口
	 */
	private void close() {
		try {
			if (mSerialPort != null) {
				if (mOutputStream != null)
					mOutputStream.close();
				if (mInputStream != null)
					mInputStream.close();
				if (mSerialPort != null)
					mSerialPort.close();
				begin = false;
				mOutputStream = null;
				mInputStream = null;
				mSerialPort = null;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	// [s] 输出
	private void writeCommand(String msg) {
		try {
			if (allowToWrite()) {
				if (msg == null)
					msg = "";
				mOutputStream.write(msg.getBytes());
				mOutputStream.flush();

			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 对扫描头写入数据，如扫描头设置参数等
	 *
	 * @param b
	 */
	public void writeCommand(byte[] b) {
		try {
			if (allowToWrite()) {
				if (b == null)
					return;
				mOutputStream.write(b);
				mOutputStream.flush(); // 1
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private boolean allowToWrite() {
		if (mOutputStream == null) {
			return false;
		}
		return true;
	}

	/**
	 * 给扫描头上下电
	 *
	 *            1 开，0关
	 */
	private void power(String p) {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		writeFile(power, p);
	}


	private void writeFile(File file, String value) {
		FileWriter writer = null;
		try {
			writer = new FileWriter(file);
			writer.write(value);
			writer.flush();
			writer.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	private Runnable countdown = new Runnable() {
		@Override
		public void run() {
			Barcode_Stop();
			isScan = false;
			if (null != onDataListener) {
				onDataListener.Barcode_timeout(scan_time);
			}

		}
	};



	/**
	 * COM口开关
	 *
	 * @param status 1开，0关
	 */
	private void com(String status) {
		writeFile(openCom, status);
	}

	/**
	 * 防止后台扫描 接受数据线程被阻断
	 */
	private static Runnable stopReceice = new Runnable() {

		@Override
		public void run() {
			setIsReceive(false);
		}
	};

	private Runnable initRunnable = new Runnable() {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			com("1");// 转换串口到扫描模块
			Barcode_Stop();
			try {
				Thread.sleep(100);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			power("1");// 给扫描头上电
		}
	};

	/**
	 * 返回数据判断处理
	 */
	private void dealData(byte[] buffer, int size) {
		try {
			if (buffer == null) {
				Barcode_Stop();
				return;
			}
			getDefault(buffer);
			cutData_buffer = null;
			cutData_buffer_size = 0;
			Barcode_Stop();
		} catch (Exception e) {
			Barcode_Stop();
			e.printStackTrace();
		}
	}

	/**
	 * 未做协议处理的数据
	 *
	 * @param buffer
	 */
	private void getDefault(byte[] buffer) {
		if (null != onDataListener) {
			onDataListener.Barcode_Read(buffer, "", 0);
			notifyScanReader();
		}
	}

	public synchronized static void setIsReceive(boolean b) {
		isReceive = b;
	}

}
